package json.org.noahx.javavsjson;

import org.apache.commons.lang3.time.DurationFormatUtils;
import org.apache.commons.lang3.time.StopWatch;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: noah
 * Date: 3/8/13
 * Time: 10:11 PM
 * To change this template use File | Settings | File Templates.
 */
public class TestRun {

    private int mapSize;

    private int loopTimes;

    public TestRun(int mapSize, int loopTimes) {
        typeList = new ArrayList<String>();
        typeList.add("String");
        typeList.add("Boolean");
        typeList.add("Integer");
        typeList.add("Long");
        typeList.add("Float");
        typeList.add("Double");

        this.mapSize = mapSize;
        this.loopTimes = loopTimes;

        System.out.println("map.size=" + mapSize);
        System.out.println("loop.times=" + loopTimes);
    }

    private List<String> typeList;

    private Map<String, Object> prepareMap() {
        Map<String, Object> map = new HashMap<String, Object>();

        int typeIndex = 0;
        for (int c = 0; c < mapSize; c++) {

            String type = typeList.get(typeIndex);
            if (type.equals("String")) {
                map.put("12345678" + c, "abcdefghijkl" + c);
            } else if (type.equals("Boolean")) {
                map.put("12345678" + c, Boolean.TRUE);
            } else if (type.equals("Integer")) {
                map.put("12345678" + c, new Integer(12345));
            } else if (type.equals("Long")) {
                map.put("12345678" + c, new Long(123456789));
            } else if (type.equals("Float")) {
                map.put("12345678" + c, new Float(12345.55));
            } else if (type.equals("Double")) {
                map.put("12345678" + c, new Double(123456789.55));
            }

            typeIndex++;
            if (typeIndex == typeList.size()) {
                typeIndex = 0;
            }
        }

        return map;
    }

    public TestResult run(SerializationTest serializationTest) {
        TestResult result = new TestResult();
        System.out.println("\n<< " + serializationTest.getTestName() + " >>");
        result.setMapSize(mapSize);
        result.setTestName(serializationTest.getTestName());

        Map<String, Object> map = prepareMap();
        StopWatch stopWatch1 = new StopWatch();
        StopWatch stopWatch2 = new StopWatch();

        byte[] bytes = serializationTest.testMap2Bytes(map);
        Map<String, Object> map2 = serializationTest.testBytes2Map(bytes);
        System.out.println(compareMap(map, map2));

        stopWatch1.start();
        for (int c = 0; c < loopTimes; c++) {
            serializationTest.testMap2Bytes(map);
        }
        stopWatch1.stop();

        stopWatch2.start();
        for (int c = 0; c < loopTimes; c++) {
            serializationTest.testBytes2Map(bytes);
        }
        stopWatch2.stop();

        result.setSerializeTime(stopWatch1.getTime());
        result.setUnserializeTime(stopWatch2.getTime());
        result.setSumTime(stopWatch1.getTime() + stopWatch2.getTime());
        result.setByteSize(bytes.length);

        System.out.println("serialize: " + stopWatch1.toString());
        System.out.println("unserialize: " + stopWatch2.toString());
        System.out.println("sum: " + DurationFormatUtils.formatDurationHMS(stopWatch1.getTime() + stopWatch2.getTime()));
        System.out.println("byte.size: " + bytes.length);

        System.out.println("<<end>>\n");

        return result;
    }

    public boolean compareMap(Map<String, Object> map1, Map<String, Object> map2) {
        if (map1.size() != map2.size()) {
            return false;
        }

        //因为gson处理Map<String,Object>这种不确定类型时，数据中的数字处理时数字都按Double处理，所以只能转换后按值比较
        for (Map.Entry<String, Object> entry1 : map1.entrySet()) {
            Object value2 = map2.get(entry1.getKey());
            if (entry1.getValue() instanceof Integer && value2 instanceof Double) {      //gson
                if ((Integer) entry1.getValue() != ((Double) value2).intValue()) {
                    return false;
                }
            } else if (entry1.getValue() instanceof Long && value2 instanceof Double) {  //gson
                if ((Long) entry1.getValue() != ((Double) value2).longValue()) {
                    return false;
                }
            } else if (entry1.getValue() instanceof Float && value2 instanceof Double) { //gson
                if ((Float) entry1.getValue() != ((Double) value2).floatValue()) {
                    return false;
                }
            } else if (entry1.getValue() instanceof Long && value2 instanceof Integer) {   //json-smart
                if ((Long) entry1.getValue() != ((Integer) value2).longValue()) {
                    return false;
                }
            } else {
                if (!entry1.getValue().equals(value2)) {
                    return false;
                }
            }

        }


        return true;
    }


}
